﻿using AspNetCoreRateLimit;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Options;
using ZR.Admin.WebApi.Filters;
using ZR.Model;
using ZR.ServiceCore.Model;
using ZR.ServiceCore.Services.IService;
using IpRateLimitPolicy = ZR.ServiceCore.Model.IpRateLimitPolicy;

namespace ZR.Admin.WebApi.Controllers.System.monitor;

[Verify]
[Route("ip/route/limit")]
public class IpRateLimitController : BaseController
{
    private readonly IpRateLimitOptions _options;
    private readonly IIpPolicyStore _ipPolicyStore;
    private readonly IIpRateLimitPolicyService _ipRateLimitPolicyService;
    private readonly IRateLimitRuleService _rateLimitRuleService;
    private readonly IIpRateLimitLogService _ipRateLimitLogService;
    
    public IpRateLimitController(IOptions<IpRateLimitOptions> optionsAccessor, IIpPolicyStore ipPolicyStore,
        IIpRateLimitPolicyService ipRateLimitPolicyService, IRateLimitRuleService rateLimitRuleService, 
        IIpRateLimitLogService ipRateLimitLogService)
    {
        _options = optionsAccessor.Value;
        _ipPolicyStore = ipPolicyStore;
        _ipRateLimitPolicyService = ipRateLimitPolicyService;
        _rateLimitRuleService = rateLimitRuleService;
        _ipRateLimitLogService = ipRateLimitLogService;
    }
    
    /// <summary>
    /// 获取限制规则
    /// </summary>
    /// <returns></returns>
    [HttpGet("getIpRateLimitPolicyPage")]
    public async Task<IActionResult> GetIpRateLimitPolicyPage([FromQuery] IpRateLimitPolicy ipRateLimitPolicy, 
        PagerInfo pager)
    {
        var page = await _ipRateLimitPolicyService.SelectIpRateLimitPolicyPageAsync(ipRateLimitPolicy, pager);
        return SUCCESS(page);
    }

    [HttpPost("addIpRateLimitPolicy")]
    public async Task<IActionResult> AddIpRateLimitPolicy([FromBody] IpRateLimitPolicy ipRateLimitPolicy)
    {
        var isExist = await _ipRateLimitPolicyService.Queryable()
            .Where(it => it.Ip == ipRateLimitPolicy.Ip)
            .AnyAsync();
        if (isExist) throw new CustomException("该IP已存在");
        var res = await _ipRateLimitPolicyService.InsertNav(ipRateLimitPolicy)
            .Include(it => it.Rules)
            .ExecuteCommandAsync();
        return SUCCESS(res);
    }

    [HttpPut("updateIpRateLimitPolicy")]
    public async Task<IActionResult> UpdateIpRateLimitPolicy(
        [FromBody] IpRateLimitPolicy ipRateLimitPolicy)
    {
        var isEnable = await _ipRateLimitPolicyService
            .Queryable()
            .Where(it => it.Id == ipRateLimitPolicy.Id
                         && it.Flag == '1')
            .AnyAsync();
        var res = await _ipRateLimitPolicyService.UpdateNav(ipRateLimitPolicy)
            .Include(it => it.Rules)
            .ExecuteCommandAsync();
        if (!isEnable) return SUCCESS(res);
        {
            await _ipPolicyStore.RemoveAsync(_options.IpPolicyPrefix);
            var ipRateLimitPolicies = _ipRateLimitPolicyService.Queryable()
                .Includes(it => it.Rules.Where(r => r.Flag == '1').ToList())
                .Where(it => it.Flag == '1')
                .ToListAsync()
                .GetAwaiter().GetResult()
                .Adapt<List<AspNetCoreRateLimit.IpRateLimitPolicy>>();
            await _ipPolicyStore.SeedAsync();
            var pol = await _ipPolicyStore.GetAsync(_options.IpPolicyPrefix);
            pol.IpRules.AddRange(ipRateLimitPolicies);
            await _ipPolicyStore.SetAsync(_options.IpPolicyPrefix, pol);
        }
        return SUCCESS(res);
    }

    [HttpPatch("enableIpRateLimitPolicy/{id}")]
    public async Task<IActionResult> EnableIpRateLimitPolicy([FromRoute] long id)
    {
        var isEnable = await _ipRateLimitPolicyService
            .Queryable()
            .Where(it => it.Id == id
                         && it.Flag == '1')
            .AnyAsync();
        if (isEnable)
        {
            throw new CustomException("已启用，无法再次启用");
        }
        await _ipRateLimitPolicyService.Updateable(new IpRateLimitPolicy
            {
                Id = id,
                Flag = '1'
            }).UpdateColumns(it => it.Flag)
            .ExecuteCommandAsync();
        var ipRateLimitPolicy = await _ipRateLimitPolicyService.Queryable()
            .Includes(it => it.Rules.Where(r => r.Flag == '1').ToList())
            .Where(it => it.Id == id)
            .SingleAsync();
        var pol = await _ipPolicyStore.GetAsync(_options.IpPolicyPrefix);
        pol.IpRules.Add(ipRateLimitPolicy.Adapt<AspNetCoreRateLimit.IpRateLimitPolicy>());
        await _ipPolicyStore.SetAsync(_options.IpPolicyPrefix, pol);
        return SUCCESS('1');
    }

    [HttpPatch("disableIpRateLimitPolicy/{id}")]
    public async Task<IActionResult> DisableIpRateLimitPolicy([FromRoute] long id)
    {
        var isEnable = await _ipRateLimitPolicyService
            .Queryable()
            .Where(it => it.Id == id
                    && it.Flag == '1')
            .AnyAsync();
        if (!isEnable)
        {
            throw new CustomException("已禁用，无法再次禁用");
        }
        await _ipRateLimitPolicyService.Updateable(new IpRateLimitPolicy
            {
                Id = id,
                Flag = '0'
            }).UpdateColumns(it => it.Flag)
            .ExecuteCommandAsync();
        var ipRateLimitPolicies = _ipRateLimitPolicyService.Queryable()
            .Includes(it => it.Rules.Where(r => r.Flag == '1').ToList())
            .Where(it => it.Flag == '1')
            .ToListAsync()
            .GetAwaiter().GetResult()
            .Adapt<List<AspNetCoreRateLimit.IpRateLimitPolicy>>();
        await _ipPolicyStore.RemoveAsync(_options.IpPolicyPrefix);
        await _ipPolicyStore.SeedAsync();
        var pol = await _ipPolicyStore.GetAsync(_options.IpPolicyPrefix);
        pol.IpRules.AddRange(ipRateLimitPolicies);
        await _ipPolicyStore.SetAsync(_options.IpPolicyPrefix, pol);
        return SUCCESS('0');
    }

    [HttpDelete("deleteIpRateLimitPolicy/{id}")]
    public async Task DeleteIpRateLimitPolicyAsync([FromRoute] long id)
    {
        var isEnable = await _ipRateLimitPolicyService
            .Queryable()
            .Where(it => it.Id == id
                         && it.Flag == '1')
            .AnyAsync();
        await _ipRateLimitPolicyService
            .DeleteNav(it => it.Id == id)
            .Include(it => it.Rules)
            .ExecuteCommandAsync();
        if (isEnable)
        {
            var ipRateLimitPolicies = _ipRateLimitPolicyService.Queryable()
                .Includes(it => it.Rules.Where(r => r.Flag == '1').ToList())
                .Where(it => it.Flag == '1')
                .ToListAsync()
                .GetAwaiter().GetResult()
                .Adapt<List<AspNetCoreRateLimit.IpRateLimitPolicy>>();
            await _ipPolicyStore.RemoveAsync(_options.IpPolicyPrefix);
            await _ipPolicyStore.SeedAsync();
            var pol = await _ipPolicyStore.GetAsync(_options.IpPolicyPrefix);
            pol.IpRules.AddRange(ipRateLimitPolicies);
            await _ipPolicyStore.SetAsync(_options.IpPolicyPrefix, pol);
        }
    }
    
    [HttpGet("getIpRateLimitLogPage")]
    public async Task<IActionResult> GetIpRateLimitLogPage([FromQuery] IpRateLimitLog ipRateLimitLog, PagerInfo pager)
    {
        return SUCCESS(await _ipRateLimitLogService.SelectIpRateLimitLogPageAsync(ipRateLimitLog, pager));
    }
    
    [HttpGet("get")]
    public async Task<IpRateLimitPolicies> Get()
    {
        return await _ipPolicyStore.GetAsync(_options.IpPolicyPrefix);
    }
    
    [HttpGet("checkIp/{ip}")]
    public async Task<IActionResult> CheckIp(string ip)
    {
        var res = await _ipRateLimitPolicyService.Queryable()
            .Where(it => it.Ip == ip)
            .AnyAsync();
        return SUCCESS(res);
    }
}